package com.idp.app.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.idp.app.dto.AppUserDto;
import com.idp.app.entity.AppUserEntity;
import com.idp.app.mapper.AppUserMapper;
import com.idp.app.service.AppLoginService;
import com.idp.common.constants.RedisKeyConstant;
import com.idp.common.enums.RegisterTypeEnum;
import com.idp.common.enums.UserStatusEnum;
import com.idp.common.enums.UserTypeEnum;
import com.idp.common.error.SystemException;
import com.idp.common.model.LoginInfo;
import com.idp.common.redis.RedisCache;
import com.idp.common.token.AppUserAuthenticationToken;
import com.idp.common.token.PhoneAuthenticationToken;
import com.idp.common.token.service.TokenService;
import com.idp.common.token.WechatAuthenticationToken;
import com.idp.common.utils.NameUtil;
import com.idp.common.utils.WechatUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * APP登录Service实现类
 * @auther king
 */
@Service
public class AppLoginServiceImpl implements AppLoginService {

	private static final Logger log = LoggerFactory.getLogger(AppLoginServiceImpl.class);

	@Autowired
	private AppUserMapper appUserMapper;
	@Autowired
	private TokenService tokenService;
	@Autowired
	private RedisCache redisCache;
	@Autowired
	private AuthenticationManager authenticationManager;

	@Override
	public LoginInfo loginPwd(String uname, String pwd, String deviceInfo) {

		return appLogin(new AppUserAuthenticationToken(uname, pwd), deviceInfo);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public LoginInfo loginWechat(String code, String deviceInfo, String phoneCode) {

		String openid = WechatUtil.code2Session(code);

		if(StrUtil.isNotEmpty(openid)) {

			String phone = "";
			if(StrUtil.isNotEmpty(phoneCode)) {
				phone = WechatUtil.getPhone(phoneCode);
			}

			AppUserDto appUser = appUserMapper.getUserByPhoneOrOpenId(phone, openid);

			if(appUser == null) {
				AppUserEntity user = new AppUserEntity();
				user.setId(IdUtil.simpleUUID());
				user.setOpenidWechatApplet(openid);
				user.setUname("U_"+NameUtil.getUniqueName());
				user.setPhone(phone);
				user.setNickname("微信用户");
				user.setStatus(UserStatusEnum.NORMAL.code);
				user.setRegisterType(RegisterTypeEnum.WECHAT_MINI_PROGRAM.code);
				user.setRegisterTime(new Date());
				user.setLoginDevice(deviceInfo);
				appUserMapper.insert(user);
			}
			else {
				AppUserEntity updateUser = new AppUserEntity();
				updateUser.setId(appUser.getId());
				updateUser.setOpenidWechatApplet(openid);
				updateUser.setPhone(phone);
				updateUser.setLoginDevice(deviceInfo);
				appUserMapper.updateById(updateUser);
			}

			return appLogin(new WechatAuthenticationToken(openid, ""), null);
		} else {
			throw new SystemException("无法授权");
		}
	}

	@Override
	public LoginInfo loginWechatAuthBase(String code, String deviceInfo) {

		String openid = WechatUtil.code2Session(code);

		if(StrUtil.isNotEmpty(openid)) {

			try {
				return appLogin(new WechatAuthenticationToken(openid, ""), deviceInfo);
			} catch (Exception e) {
				return null;
			}
		}

		return null;
	}

	@Override
	public void getSmsCode(String phone) {

		if(StrUtil.isNotEmpty(phone)) {

			Double num = Math.random() * 9000 + 1000;
			String code = String.valueOf(num.intValue());

			// 手机验证码有效期5分钟
			redisCache.saveObject(RedisKeyConstant.PHONE_FOLDER + phone, code, 5);
			// TODO 发送短信
			System.err.println("验证码:" + code);
		} else {
			throw new SystemException("手机号不能为空");
		}
	}

	@Override
	public LoginInfo checkSmsCode(String phone, String smsCode) {

		String cacheCode = redisCache.getObject(RedisKeyConstant.PHONE_FOLDER + phone);

		if(smsCode.equals(cacheCode)) {
			return appLogin(new PhoneAuthenticationToken(phone, ""), null);
		} else {
			throw new SystemException("验证码错误");
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public LoginInfo loginSms(String phone, String smsCode, String deviceInfo) {

		String cacheCode = redisCache.getObject(RedisKeyConstant.PHONE_FOLDER + phone);

		if(smsCode.equals(cacheCode)) {

			LambdaQueryWrapper<AppUserEntity> query = new LambdaQueryWrapper<AppUserEntity>();
			query.eq(AppUserEntity::getPhone, phone);
			AppUserEntity userEntity = appUserMapper.selectOne(query);

			if(userEntity == null) {
				AppUserEntity user = new AppUserEntity();
				user.setId(IdUtil.simpleUUID());
				user.setUname("U_"+NameUtil.getUniqueName());
				user.setPhone(phone);
				user.setNickname("手机用户");
				user.setStatus(UserStatusEnum.NORMAL.code);
				user.setRegisterType(RegisterTypeEnum.APP_PHONE.code);
				user.setRegisterTime(new Date());
				user.setLoginDevice(deviceInfo);
				appUserMapper.insert(user);
			}

			return appLogin(new PhoneAuthenticationToken(phone, ""), deviceInfo);
		} else {
			throw new SystemException("验证码错误");
		}
	}

	private LoginInfo appLogin(Authentication authenticationToken, String deviceInfo) {

		Authentication authentication = authenticationManager.authenticate(authenticationToken);

		LoginInfo loginInfo = (LoginInfo) authentication.getPrincipal();
		loginInfo.setUserType(UserTypeEnum.MOBILE.code);
		tokenService.saveToken(loginInfo);

		if(StrUtil.isNotEmpty(deviceInfo)) {
			AppUserEntity updateUser = new AppUserEntity();
			updateUser.setId(loginInfo.getId());
			updateUser.setLoginDevice(deviceInfo);
			appUserMapper.updateById(updateUser);
		}

		return loginInfo;
	}
}
